<?php

namespace App\Helpers;

use App\Exceptions\BusinessException;
use App\Models\AqConversation;
use App\Models\AqConversationDetail;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;

class BailianChatHelper
{
	public static $request_id;

	public static function getId()
	{
		return self::$request_id;
	}

	public static function send($apiKey,$app_id,$data,$detail_id,$prefixText = '')
	{
		$url = 'https://dashscope.aliyuncs.com/api/v1/apps/'.$app_id.'/completion';
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_POST, true);
		curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
		curl_setopt($ch, CURLOPT_HTTPHEADER, array(
			'Authorization: Bearer ' . $apiKey,
			'Content-Type: application/json',
			'X-DashScope-SSE: enable'
		));
		curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) use($detail_id) {
			preg_match('/^data:(.*)$/m', $data, $matches);
			if (!empty($matches[1])) {
				$response = json_decode($matches[1], true);
				$text = Arr::get($response,'output.text');
				$finish_reason = Arr::get($response,'output.finish_reason');
				$content = cache()->get('conversation:text:'.$detail_id);
				$datas = cache()->get('conversation:data:'.$detail_id);
				$datas[] = $response;
				cache()->put('conversation:data:'.$detail_id,$datas);
				cache()->put('conversation:text:'.$detail_id,$content.$text);
				self::eventsourceMessage($text, $finish_reason);
			}
			return strlen($data);
		});
		curl_exec($ch);
		curl_close($ch);
	}

	public static function finished($id,$isBroken = false)
	{
		$text = cache()->get('conversation:text:'.$id);
		$data = cache()->get('conversation:data:'.$id);
		$detail = AqConversationDetail::find($id);
		$detail->update([
				'response_text' => $text.($isBroken ? '[中断]' : ''),
				'response_data' => $data,
				'request_id' => Arr::get(Arr::first($data),'request_id')
			]);
		$detail->conversation->update([
			'session_id' => Arr::get(Arr::first($data),'output.session_id')
		]);
	}

	// 终止链接事件，并返回错误信息
	public static function eventsourceClose($error)
	{
		self::eventsourceMessage($error, 'stop');
		die;
	}

	public static function eventStart($id = null)
	{
		self::setResponseHeaders();
		self::$request_id = $id ? : Str::uuid();
	}

	//发送消息
	public static function eventsourceMessage($message,$finish_reason = null)
	{
		$data = [
			'id' => self::$request_id,
			'choices' => [
				[
					'index' => 0,
					'delta' => [
						'role' => 'assistant',
						'content' => $message
					],
					'finish_reason' => $finish_reason
				]
			]
		];
		$string ='data: '. json_encode($data) . PHP_EOL . PHP_EOL;
		echo $string;
		if (ob_get_level() > 0) {
			ob_flush();
		}
		flush();
	}

	public static function eventSourceEvent($message)
	{
		$data = [
			'id' => self::$request_id,
			'choices' => [
				[
					'index' => 0,
					'delta' => [
						'role' => 'system',
						'content' => '',
						'message' => $message
					],
					'finish_reason' => null
				]
			]
		];
		$string ='data: '. json_encode($data) . PHP_EOL . PHP_EOL;
		echo $string;
		if (ob_get_level() > 0) {
			ob_flush();
		}
		flush();
	}

	public static function eventSourceData($eventData)
	{
		$data = [
			'id' => self::$request_id,
			'choices' => [
				[
					'index' => 0,
					'delta' => [
						'role' => 'event',
						'content' => '',
						'event_data' => $eventData
					],
					'finish_reason' => null
				]
			]
		];
		$string ='data: '. json_encode($data) . PHP_EOL . PHP_EOL;
		echo $string;
		if (ob_get_level() > 0) {
			ob_flush();
		}
		flush();
	}

	// 设置响应头
	public static function setResponseHeaders(){
		header_remove();
		ob_end_clean();
		ob_implicit_flush();
		header("X-Accel-Buffering: no");
		header('Content-Type: text/event-stream');
		header('Cache-Control: no-cache');
		header('Connection: keep-alive');
		header('Access-Control-Allow-Origin: *');
		ob_start();

	}

	//解析图片
	public static function parseImage($attachs,$model)
	{
		$content = [];
		foreach ($attachs as $file){
			$filepath = $file['path'];
			$type = mime_content_type($filepath);
			$content[] = [
				'type' => 'image_url',
				'image_url' => [
					'url' => 'data:'.$type.';base64,'.base64_encode(file_get_contents($filepath))
				]
			];
		}
		$content[] = [
			'type' => 'text',
			'text' => $model->image_prompt
		];
		$data = [
			'model' => $model->image_model,
			'messages' => [
				[
					'role' => 'user',
					'content' => $content
				]
			]
		];
		$json = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

		$curl = curl_init();
		curl_setopt_array($curl, array(
			CURLOPT_URL => 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions',
			CURLOPT_RETURNTRANSFER => true,
			CURLOPT_ENCODING => '',
			CURLOPT_MAXREDIRS => 10,
			CURLOPT_TIMEOUT => 99999,
			CURLOPT_CONNECTTIMEOUT => 99999,
			CURLOPT_FOLLOWLOCATION => true,
			CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
			CURLOPT_CUSTOMREQUEST => 'POST',
			CURLOPT_POSTFIELDS => $json,
			CURLOPT_HTTPHEADER => array(
				'Authorization: Bearer '.$model->api_key,
				'Content-Type: application/json',
				'Content-Length: '.strlen($json)
			),
		));

		$response = curl_exec($curl);

		curl_close($curl);
		$data = json_decode($response,true);
		return Arr::get($data,'choices.0.message.content');
	}

	//处理文档
	public static function parseDocument($attachs,$model){
		$fileIds = [];
		foreach ($attachs as $file)
		{
			$filepath = $file['path'];
			$res = AiFileUploadHelper::ApplyFileUploadLease($filepath);
			AiFileUploadHelper::UploadFile( $res->param->url,$filepath,$res->param->headers);
			$fileIds[] = AiFileUploadHelper::AddFile($res->fileUploadLeaseId);
		}
		$readFileIds = $fileIds;
		while(true){
			if(empty($fileIds)){
				break;
			}
			foreach ($fileIds as $key => $fileId){
			  	$status =	AiFileUploadHelper::CheckFile($fileId);
				if($status == 'FILE_IS_READY'){
					unset($fileIds[$key]);
				}elseif(
					empty($status) ||
					in_array(
						strtoupper($status),
						array('FILE_UPLOAD_FAILED','FILE_UPLOAD_FAILED_TOO_LARGE')
					)
				){
					\Log::error('上传文件失败：'.$fileId);
					\Log::error('上传文件失败：'.($status ? : 'MISSING STATUS'));
					throw new BusinessException('上传文件失败：'.($status ? : 'MISSING STATUS'));
				}
			}
			self::eventsourceMessage('');
			sleep(mt_rand(1,5));
		}
		return $readFileIds;
	}

}
